package metrics

import (
	"fmt"
	"sync"
	"time"

	"metrics-collect/pkg/plugins"

	"go.uber.org/zap"
)

// CollectorManager manages the metric collectors
type CollectorManager struct {
	plugins map[string]plugins.Plugin
	server  *Server
	logger  *zap.Logger
	mu      sync.RWMutex
}

// NewCollectorManager creates a new collector manager
func NewCollectorManager(server *Server, logger *zap.Logger) *CollectorManager {
	return &CollectorManager{
		plugins: make(map[string]plugins.Plugin),
		server:  server,
		logger:  logger,
	}
}

// RegisterPlugin registers a new plugin
func (m *CollectorManager) RegisterPlugin(plugin plugins.Plugin) error {
	m.mu.Lock()
	defer m.mu.Unlock()

	name := plugin.Name()
	if _, exists := m.plugins[name]; exists {
		return fmt.Errorf("plugin %s already registered", name)
	}

	// Register all metrics with Prometheus
	for _, metric := range plugin.GetMetrics() {
		if err := m.server.RegisterCollector(metric); err != nil {
			return fmt.Errorf("failed to register metrics for plugin %s: %v", name, err)
		}
	}

	m.plugins[name] = plugin
	return nil
}

// StartPlugin starts a specific plugin
func (m *CollectorManager) StartPlugin(name string) error {
	m.mu.RLock()
	plugin, exists := m.plugins[name]
	m.mu.RUnlock()

	if !exists {
		return fmt.Errorf("plugin %s not found", name)
	}

	if err := plugin.Start(); err != nil {
		return fmt.Errorf("failed to start plugin %s: %v", name, err)
	}

	m.logger.Info("Started plugin", zap.String("plugin", name))
	return nil
}

// StopPlugin stops a specific plugin
func (m *CollectorManager) StopPlugin(name string) error {
	m.mu.RLock()
	plugin, exists := m.plugins[name]
	m.mu.RUnlock()

	if !exists {
		return fmt.Errorf("plugin %s not found", name)
	}

	if err := plugin.Stop(); err != nil {
		return fmt.Errorf("failed to stop plugin %s: %v", name, err)
	}

	m.logger.Info("Stopped plugin", zap.String("plugin", name))
	return nil
}

// InitializePlugin initializes a plugin with its configuration
func (m *CollectorManager) InitializePlugin(name string, config map[string]interface{}, interval time.Duration) error {
	m.mu.RLock()
	plugin, exists := m.plugins[name]
	m.mu.RUnlock()

	if !exists {
		return fmt.Errorf("plugin %s not found", name)
	}

	if basePlugin, ok := plugin.(interface{ SetInterval(time.Duration) }); ok {
		basePlugin.SetInterval(interval)
	}

	if err := plugin.Init(config); err != nil {
		return fmt.Errorf("failed to initialize plugin %s: %v", name, err)
	}

	m.logger.Info("Initialized plugin",
		zap.String("plugin", name),
		zap.Duration("interval", interval),
	)
	return nil
}

// GetPlugin returns a plugin by name
func (m *CollectorManager) GetPlugin(name string) (plugins.Plugin, bool) {
	m.mu.RLock()
	defer m.mu.RUnlock()
	plugin, exists := m.plugins[name]
	return plugin, exists
}
